{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](https://europe-west1-atp-views-tracker.cloudfunctions.net/working-analytics?notebook=tutorials--langgraph-agent--langgraph-tutorial)\n",
    "\n",
    "# LangGraph Tutorial: Building a Text Analysis Pipeline\n",
    "\n",
    "## Introduction to LangGraph\n",
    "\n",
    "LangGraph is a powerful framework by LangChain designed for creating stateful, multi-actor applications with LLMs. It provides the structure and tools needed to build sophisticated AI agents through a graph-based approach.\n",
    "\n",
    "Think of LangGraph as an architect's drafting table - it gives us the tools to design how our agent will think and act. Just as an architect draws blueprints showing how different rooms connect and how people will flow through a building, LangGraph lets us design how different capabilities will connect and how information will flow through our agent.\n",
    "\n",
    "### Key Features:\n",
    "- **State Management:** Maintain persistent state across interactions\n",
    "- **Flexible Routing:** Define complex flows between components\n",
    "- **Persistence:** Save and resume workflows\n",
    "- **Visualization:** See and understand your agent's structure\n",
    "\n",
    "In this tutorial, we'll demonstrate LangGraph by building a multi-step text analysis pipeline that processes text through three stages:\n",
    "1. **Text Classification:** Categorize input text into predefined categories\n",
    "2. **Entity Extraction:** Identify key entities from the text\n",
    "3. **Text Summarization:** Generate a concise summary of the input text\n",
    "\n",
    "This pipeline showcases how LangGraph can be used to create a modular, extensible workflow for natural language processing tasks."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "📖 **For more background on building AI agents and getting started, check out our detailed blog post:** [Your First AI Agent: Simpler Than You Think](https://open.substack.com/pub/diamantai/p/your-first-ai-agent-simpler-than?r=336pe4&utm_campaign=post&utm_medium=web&showWelcomeOnShare=false)\n",
    "\n",
    "*DiamantAI is a top 0.1% newsletter for AI with over 25,000 subscribers, focusing on AI techniques, breakthroughs, and tutorials.*\n",
    "\n",
    "---\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Setting Up Our Environment\n",
    "\n",
    "Before diving into the code, let's set up our development environment."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Install required packages\n",
    "!pip install langgraph langchain langchain-openai python-dotenv"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Setting Up API Keys\n",
    "\n",
    "We'll need an OpenAI API key to use their models. If you haven't already, you can get one from [https://platform.openai.com/signup](https://platform.openai.com/signup).\n",
    "\n",
    "Let's load our environment variables:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# Load environment variables from .env file (create this with your API key)\n",
    "load_dotenv()\n",
    "\n",
    "# Set OpenAI API key\n",
    "os.environ[\"OPENAI_API_KEY\"] = os.getenv('OPENAI_API_KEY')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Testing Our Setup\n",
    "\n",
    "Let's make sure our environment is working correctly by creating a simple test with the OpenAI model:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Hello! Yes, I'm here and ready to help you. What can I assist you with today?\n"
     ]
    }
   ],
   "source": [
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "# Initialize the ChatOpenAI instance\n",
    "llm = ChatOpenAI(model=\"gpt-4o-mini\")\n",
    "\n",
    "# Test the setup\n",
    "response = llm.invoke(\"Hello! Are you working?\")\n",
    "print(response.content)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Building Our Text Analysis Pipeline\n",
    "\n",
    "Now let's import the necessary packages for our LangGraph text analysis pipeline:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from typing import TypedDict, List, Annotated\n",
    "from langgraph.graph import StateGraph, END\n",
    "from langchain_core.prompts import PromptTemplate\n",
    "from langchain_openai import ChatOpenAI\n",
    "from langchain_core.messages import HumanMessage\n",
    "from langchain_core.runnables.graph import MermaidDrawMethod\n",
    "from IPython.display import display, Image"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Designing Our Agent's Memory\n",
    "\n",
    "Just as human intelligence requires memory, our agent needs a way to keep track of information. We create this using a TypedDict to define our state structure:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "class State(TypedDict):\n",
    "    text: str\n",
    "    classification: str\n",
    "    entities: List[str]\n",
    "    summary: str\n",
    "\n",
    "# Initialize our language model with temperature=0 for more deterministic outputs\n",
    "llm = ChatOpenAI(model=\"gpt-4o-mini\", temperature=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Creating Our Agent's Core Capabilities\n",
    "\n",
    "Now we'll create the actual skills our agent will use. Each of these capabilities is implemented as a function that performs a specific type of analysis.\n",
    "\n",
    "#### 1. Classification Node"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def classification_node(state: State):\n",
    "    '''Classify the text into one of the categories: News, Blog, Research, or Other'''\n",
    "    prompt = PromptTemplate(\n",
    "        input_variables=[\"text\"],\n",
    "        template=\"Classify the following text into one of the categories: News, Blog, Research, or Other.\\n\\nText:{text}\\n\\nCategory:\"\n",
    "    )\n",
    "    message = HumanMessage(content=prompt.format(text=state[\"text\"]))\n",
    "    classification = llm.invoke([message]).content.strip()\n",
    "    return {\"classification\": classification}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 2. Entity Extraction Node"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def entity_extraction_node(state: State):\n",
    "    '''Extract all the entities (Person, Organization, Location) from the text'''\n",
    "    prompt = PromptTemplate(\n",
    "        input_variables=[\"text\"],\n",
    "        template=\"Extract all the entities (Person, Organization, Location) from the following text. Provide the result as a comma-separated list.\\n\\nText:{text}\\n\\nEntities:\"\n",
    "    )\n",
    "    message = HumanMessage(content=prompt.format(text=state[\"text\"]))\n",
    "    entities = llm.invoke([message]).content.strip().split(\", \")\n",
    "    return {\"entities\": entities}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 3. Summarization Node"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def summarization_node(state: State):\n",
    "    '''Summarize the text in one short sentence'''\n",
    "    prompt = PromptTemplate(\n",
    "        input_variables=[\"text\"],\n",
    "        template=\"Summarize the following text in one short sentence.\\n\\nText:{text}\\n\\nSummary:\"\n",
    "    )\n",
    "    message = HumanMessage(content=prompt.format(text=state[\"text\"]))\n",
    "    summary = llm.invoke([message]).content.strip()\n",
    "    return {\"summary\": summary}"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Bringing It All Together\n",
    "\n",
    "Now comes the most exciting part - connecting these capabilities into a coordinated system using LangGraph:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Create our StateGraph\n",
    "workflow = StateGraph(State)\n",
    "\n",
    "# Add nodes to the graph\n",
    "workflow.add_node(\"classification_node\", classification_node)\n",
    "workflow.add_node(\"entity_extraction\", entity_extraction_node)\n",
    "workflow.add_node(\"summarization\", summarization_node)\n",
    "\n",
    "# Add edges to the graph\n",
    "workflow.set_entry_point(\"classification_node\")  # Set the entry point of the graph\n",
    "workflow.add_edge(\"classification_node\", \"entity_extraction\")\n",
    "workflow.add_edge(\"entity_extraction\", \"summarization\")\n",
    "workflow.add_edge(\"summarization\", END)\n",
    "\n",
    "# Compile the graph\n",
    "app = workflow.compile()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Visualizing the Workflow\n",
    "\n",
    "One of the powerful features of LangGraph is the ability to visualize our workflow:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Display a visualization of our graph\n",
    "try:\n",
    "    display(\n",
    "        Image(\n",
    "            app.get_graph().draw_mermaid_png(\n",
    "                draw_method=MermaidDrawMethod.API,\n",
    "            )\n",
    "        )\n",
    "    )\n",
    "except Exception as e:\n",
    "    print(f\"Error generating visualization: {e}\")\n",
    "    print(\"The graph structure is: classification_node -> entity_extraction -> summarization -> END\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Testing Our Agent\n",
    "\n",
    "Now that we've built our agent, let's see how it performs with a real-world text example:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classification: News\n",
      "\n",
      "Entities: ['OpenAI', 'GPT-4', 'GPT-3']\n",
      "\n",
      "Summary: OpenAI's upcoming GPT-4 model is a multimodal AI that aims for human-level performance and improved safety, efficiency, and scalability compared to GPT-3.\n"
     ]
    }
   ],
   "source": [
    "sample_text = \"\"\"\n",
    "OpenAI has announced the GPT-4 model, which is a large multimodal model that exhibits human-level performance on various professional benchmarks. It is developed to improve the alignment and safety of AI systems.\n",
    "Additionally, the model is designed to be more efficient and scalable than its predecessor, GPT-3. The GPT-4 model is expected to be released in the coming months and will be available to the public for research and development purposes.\n",
    "\"\"\"\n",
    "\n",
    "state_input = {\"text\": sample_text}\n",
    "result = app.invoke(state_input)\n",
    "\n",
    "print(\"Classification:\", result[\"classification\"])\n",
    "print(\"\\nEntities:\", result[\"entities\"])\n",
    "print(\"\\nSummary:\", result[\"summary\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Understanding the Power of Coordinated Processing\n",
    "\n",
    "What makes this result particularly impressive isn't just the individual outputs - it's how each step builds on the others to create a complete understanding of the text.\n",
    "\n",
    "- The **classification** provides context that helps frame our understanding of the text type\n",
    "- The **entity extraction** identifies important names and concepts\n",
    "- The **summarization** distills the essence of the document\n",
    "\n",
    "This mirrors human reading comprehension, where we naturally form an understanding of what kind of text it is, note important names and concepts, and form a mental summary - all while maintaining the relationships between these different aspects of understanding."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Try with Your Own Text\n",
    "\n",
    "Now let's try our pipeline with another text sample of your choice:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classification: Research\n",
      "\n",
      "Entities: ['MIT', 'Google']\n",
      "\n",
      "Summary: Recent advancements in quantum computing may threaten current encryption methods while also prompting the development of new quantum-resistant techniques.\n"
     ]
    }
   ],
   "source": [
    "# Replace this with your own text to analyze\n",
    "your_text = \"\"\"\n",
    "The recent advancements in quantum computing have opened new possibilities for cryptography and data security. \n",
    "Researchers at MIT and Google have demonstrated quantum algorithms that could potentially break current encryption methods.\n",
    "However, they are also developing new quantum-resistant encryption techniques to protect data in the future.\n",
    "\"\"\"\n",
    "\n",
    "# Process the text through our pipeline\n",
    "your_result = app.invoke({\"text\": your_text})\n",
    "\n",
    "print(\"Classification:\", your_result[\"classification\"])\n",
    "print(\"\\nEntities:\", your_result[\"entities\"])\n",
    "print(\"\\nSummary:\", your_result[\"summary\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding More Capabilities (Advanced)\n",
    "\n",
    "One of the powerful aspects of LangGraph is how easily we can extend our agent with new capabilities. Let's add a sentiment analysis node to our pipeline:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "# First, let's update our State to include sentiment\n",
    "class EnhancedState(TypedDict):\n",
    "    text: str\n",
    "    classification: str\n",
    "    entities: List[str]\n",
    "    summary: str\n",
    "    sentiment: str\n",
    "\n",
    "# Create our sentiment analysis node\n",
    "def sentiment_node(state: EnhancedState):\n",
    "    '''Analyze the sentiment of the text: Positive, Negative, or Neutral'''\n",
    "    prompt = PromptTemplate(\n",
    "        input_variables=[\"text\"],\n",
    "        template=\"Analyze the sentiment of the following text. Is it Positive, Negative, or Neutral?\\n\\nText:{text}\\n\\nSentiment:\"\n",
    "    )\n",
    "    message = HumanMessage(content=prompt.format(text=state[\"text\"]))\n",
    "    sentiment = llm.invoke([message]).content.strip()\n",
    "    return {\"sentiment\": sentiment}\n",
    "\n",
    "# Create a new workflow with the enhanced state\n",
    "enhanced_workflow = StateGraph(EnhancedState)\n",
    "\n",
    "# Add the existing nodes\n",
    "enhanced_workflow.add_node(\"classification_node\", classification_node)\n",
    "enhanced_workflow.add_node(\"entity_extraction\", entity_extraction_node)\n",
    "enhanced_workflow.add_node(\"summarization\", summarization_node)\n",
    "\n",
    "# Add our new sentiment node\n",
    "enhanced_workflow.add_node(\"sentiment_analysis\", sentiment_node)\n",
    "\n",
    "# Create a more complex workflow with branches\n",
    "enhanced_workflow.set_entry_point(\"classification_node\")\n",
    "enhanced_workflow.add_edge(\"classification_node\", \"entity_extraction\")\n",
    "enhanced_workflow.add_edge(\"entity_extraction\", \"summarization\")\n",
    "enhanced_workflow.add_edge(\"summarization\", \"sentiment_analysis\")\n",
    "enhanced_workflow.add_edge(\"sentiment_analysis\", END)\n",
    "\n",
    "# Compile the enhanced graph\n",
    "enhanced_app = enhanced_workflow.compile()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Testing the Enhanced Agent"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classification: News\n",
      "\n",
      "Entities: ['OpenAI', 'GPT-4', 'GPT-3']\n",
      "\n",
      "Summary: OpenAI's upcoming GPT-4 model is a multimodal AI that aims for human-level performance and improved safety, efficiency, and scalability compared to GPT-3.\n",
      "\n",
      "Sentiment: The sentiment of the text is Positive. It highlights the advancements and improvements of the GPT-4 model, emphasizing its human-level performance, efficiency, scalability, and the positive implications for AI alignment and safety. The anticipation of its release for public use further contributes to the positive tone.\n"
     ]
    }
   ],
   "source": [
    "# Try the enhanced pipeline with the same text\n",
    "enhanced_result = enhanced_app.invoke({\"text\": sample_text})\n",
    "\n",
    "print(\"Classification:\", enhanced_result[\"classification\"])\n",
    "print(\"\\nEntities:\", enhanced_result[\"entities\"])\n",
    "print(\"\\nSummary:\", enhanced_result[\"summary\"])\n",
    "print(\"\\nSentiment:\", enhanced_result[\"sentiment\"])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Adding Conditional Edges to the LangGraph Pipeline(Advanced Logic)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Why **Conditional Edges**?\n",
    "\n",
    "So far, our graph has followed a fixed linear path:\n",
    "\n",
    "classification_node → entity_extraction → summarization → (sentiment)\n",
    "\n",
    "But in real-world applications, we often want to run certain steps only if needed. For example:\n",
    "\n",
    "- Only extract entities if the text is a News or Research article.\n",
    "\n",
    "- Skip summarization if the text is very short.\n",
    "\n",
    "- Add custom processing for Blog posts.\n",
    "\n",
    "LangGraph makes this easy through conditional edges-logic gates that dynamically route execution based on data in the current state."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 1. Update the State\n",
    "We'll use the same EnhancedState from the advanced section:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "class EnhancedState(TypedDict):\n",
    "    text: str\n",
    "    classification: str\n",
    "    entities: List[str]\n",
    "    summary: str\n",
    "    sentiment: str"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 2. Create a Routing Function\n",
    "This function routes based on classification:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Route after classification\n",
    "def route_after_classification(state: EnhancedState) -> str:\n",
    "    category = state[\"classification\"].lower() # returns: \"news\", \"blog\", \"research\", \"other\"\n",
    "    return category in [\"news\", \"research\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 3. Define the Graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langgraph.graph import StateGraph, END\n",
    "\n",
    "conditional_workflow = StateGraph(EnhancedState)\n",
    "\n",
    "# Add nodes\n",
    "conditional_workflow.add_node(\"classification_node\", classification_node)\n",
    "conditional_workflow.add_node(\"entity_extraction\", entity_extraction_node)\n",
    "conditional_workflow.add_node(\"summarization\", summarization_node)\n",
    "conditional_workflow.add_node(\"sentiment_analysis\", sentiment_node)\n",
    "\n",
    "# Set entry point\n",
    "conditional_workflow.set_entry_point(\"classification_node\")\n",
    "\n",
    "# Add conditional edge\n",
    "conditional_workflow.add_conditional_edges(\"classification_node\", route_after_classification, path_map={\n",
    "    True: \"entity_extraction\",\n",
    "    False: \"summarization\"\n",
    "})\n",
    "\n",
    "# Add remaining static edges\n",
    "conditional_workflow.add_edge(\"entity_extraction\", \"summarization\")\n",
    "conditional_workflow.add_edge(\"summarization\", \"sentiment_analysis\")\n",
    "conditional_workflow.add_edge(\"sentiment_analysis\", END)\n",
    "\n",
    "# Compile\n",
    "conditional_app = conditional_workflow.compile()\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 4. Visualize"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "\n",
    "try:\n",
    "    display(Image(\n",
    "        conditional_app.get_graph().draw_mermaid_png()\n",
    "    ))\n",
    "except:\n",
    "    print(\"Graph: classification_node → (conditional) → [entity_extraction or summarization] → sentiment_analysis → END\")\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 5. Test the Conditional Pipeline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classification: News\n",
      "Entities: ['OpenAI', 'GPT-4']\n",
      "Summary: OpenAI's GPT-4 model significantly improves performance in academic and professional tasks, marking a breakthrough in alignment and reasoning.\n",
      "Sentiment: The sentiment of the text is Positive. It highlights the release of the GPT-4 model as a significant advancement, emphasizing its enhanced performance and breakthrough capabilities.\n"
     ]
    }
   ],
   "source": [
    "test_text = \"\"\"\n",
    "OpenAI released the GPT-4 model with enhanced performance on academic and professional tasks. It's seen as a major breakthrough in alignment and reasoning capabilities.\n",
    "\"\"\"\n",
    "\n",
    "result = conditional_app.invoke({\"text\": test_text})\n",
    "\n",
    "print(\"Classification:\", result[\"classification\"])\n",
    "print(\"Entities:\", result.get(\"entities\", \"Skipped\"))\n",
    "print(\"Summary:\", result[\"summary\"])\n",
    "print(\"Sentiment:\", result[\"sentiment\"])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now try it with a Blog:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classification: Blog\n",
      "Entities: Skipped (not applicable)\n",
      "Summary: A week of silent meditation led to profound personal insights.\n",
      "Sentiment: The sentiment of the text is Positive. The mention of \"deep realizations\" and the overall reflective nature of the experience suggests a beneficial and enlightening outcome from the meditation practice.\n"
     ]
    }
   ],
   "source": [
    "blog_text = \"\"\"\n",
    "Here's what I learned from a week of meditating in silence. No phones, no talking—just me, my breath, and some deep realizations.\n",
    "\"\"\"\n",
    "\n",
    "result = conditional_app.invoke({\"text\": blog_text})\n",
    "\n",
    "print(\"Classification:\", result[\"classification\"])\n",
    "print(\"Entities:\", result.get(\"entities\", \"Skipped (not applicable)\"))\n",
    "print(\"Summary:\", result[\"summary\"])\n",
    "print(\"Sentiment:\", result[\"sentiment\"])\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "With conditional edges, our agent can now:\n",
    "\n",
    "- Make decisions based on context\n",
    "\n",
    "- Skip unnecessary steps\n",
    "\n",
    "- Run faster and cheaper\n",
    "\n",
    "- Behave more intelligently"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "In this tutorial, we've:\n",
    "\n",
    "1. Explored LangGraph concepts and its graph-based approach\n",
    "2. Built a text processing pipeline with classification, entity extraction, and summarization\n",
    "3. Enhanced our pipeline with additional capabilities\n",
    "4. Introduced conditional edges to dynamically control the flow based on classification results\n",
    "5. Visualized our workflow\n",
    "6. Tested our agent with real-world text examples\n",
    "\n",
    "LangGraph provides a powerful framework for creating AI agents by modeling them as graphs of capabilities. This approach makes it easy to design, modify, and extend complex AI systems.\n",
    "\n",
    "### Next Steps\n",
    "\n",
    "- Add more nodes to extend your agent's capabilities\n",
    "- Experiment with different LLMs and parameters\n",
    "- Explore LangGraph's state persistence features for ongoing conversations\n",
    "\n",
    "For more information, check out the official LangGraph documentation at https://langchain-ai.github.io/langgraph/"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "tf",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.8"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
